package chapter9.exercise2;


/**
 * 设计一个生产电脑和搬运电脑类，要求生产出一台电脑就搬走一台电脑，如果没有新的电脑生产
 * 出来，则搬运工要等待新电脑产出；如果生产出的电脑没有搬走，则要等待电脑搬走之后再生产，
 * 并统计出生产的电脑数量
 * @author libojuve@gmail.com
 *
 */
public class Exercise2Solution2 {
	public static void main(String[] args) {
		final ComputerQueue queue = new ComputerQueue();

		Thread tProduce = new Thread(new Runnable() {
			private int nbComputer = 0;

			@Override
			public void run() {
				while (nbComputer < 10) {
					queue.putComputer();
					++nbComputer;
					System.out.println("生产了" + nbComputer + "台电脑");
				}
			}
		});

		tProduce.setName("Producer");

		Thread tTransporter = new Thread(new Runnable() {
			private int nbComputer = 0;

			@Override
			public void run() {
				while (nbComputer < 10) {
					queue.transportComputer();
					++nbComputer;
					System.out.println("搬运了" + nbComputer + "台电脑");
				}

			}
		});

		tTransporter.setName("Transporter");

		tProduce.start();
		tTransporter.start();

	}
}

/**
 * 一个假想的电脑队列，用来同步生产类和搬运类
 * @author libojuve@gmail.com
 *
 */
class ComputerQueue {
	/**
	 * 因为队列只能放一个东西，也可以用boolean代替
	 * 用int为以后扩展之用
	 */
	private int nbComputer;

	public ComputerQueue() {
		// 最开始队列没电脑
		nbComputer = 0;
	}

	public synchronized void putComputer() {
		String threadName = Thread.currentThread().getName();
		try {
			// 先检查对列是否满了
			while (isFull()) {
				System.out.println("线程" + threadName + "先等一会儿");
				wait();
			}
			// 此时队列空了
			System.out.println("线程" + threadName + "生产一台电脑！");
			++nbComputer;
			// 唤醒有可能等nbComputer == 1的线程
			notifyAll();
		}
		catch (InterruptedException e) {
			System.out.println("线程" + threadName +  "被打断了！");
		}
	}

	public synchronized void transportComputer() {
		String threadName = Thread.currentThread().getName();
		try {
			// 先检查是否有电脑，如果没有就等待
			while (isEmpty()) {
				System.out.println("线程" + threadName + "先等一会儿");
				wait();
			}
			// 此时线程被唤醒，有电脑可搬
			System.out.println("线程" + threadName + "搬运了一台电脑！");
			--nbComputer;
			// 唤醒有可能等nbComputer == 0的线程
			notifyAll();
		}
		catch (InterruptedException e) {
			System.out.println("线程" + threadName +  "被打断了！");
		}
	}

	private synchronized boolean isFull() {
		return nbComputer == 1;
	}

	private synchronized boolean isEmpty() {
		return nbComputer == 0;
	}

}
